#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <memory>

#include <cstring>

#include <sys/types.h>
#include <sys/socket.h>
#include <json/json.h>

// 定义空格
#define SEP " "
#define SEP_LEN strlen(SEP) // 不要使用sizeof
#define LINE_SEP "\r\n"
#define LINE_SEP_LEN strlen(LINE_SEP)

enum
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERR
};

// 协议定制，我们可以定义很多不同的协议，比如100个协议，根据协议编号确定有效载荷使用的是何种协议
//  contex_len\r\nx op y\r\n -> "contex_len\r\n协议编号\r\nx op y\r\n"

// 1.添加,删除长度
// x op y -> contex_len\r\nx op y\r\n
// exitcode result -> contex_len\r\n exitcode result\r\n
const std::string enLength(const std::string &test)
{
    // 给发送的数据添加报头
    std::string send_string = std::to_string(test.size());
    send_string += LINE_SEP;
    send_string += test;
    send_string += LINE_SEP;

    return send_string;
}

// 删除报头，分隔符
// contex_len\r\nx op y\r\n            -> x op y
// contex_len\r\nexitcode result\r\n   -> exitcode result
bool deLength(const std::string &package, std::string *rcv_str)
{
    // 删除接收数据的报头
    auto pos = package.find(LINE_SEP);
    if (pos == std::string::npos)
        return false;
    std::string text_len_string = package.substr(0, pos);
    int text_len = stoi(text_len_string);

    *rcv_str = package.substr(pos + LINE_SEP_LEN, text_len);
    return true;
}

// 根据协议处理接收的信息
// "contex_len\r\nx op y\r\n""contex_len\r\nx op y\r\n""contex_len\r\nx op"
bool ParseOnePackage(std::string &inbuffer, std::string *rcv_text)
{
    rcv_text->clear();
    // 1.判断有无分隔符
    auto pos = inbuffer.find(LINE_SEP);
    if (pos == std::string::npos) // 发现报文不完整没有分隔符，需要重新读取新数据
        return false;

    // 2.到这里，说明读取到了一个\r\n。判断inbuffer中有无一个完整的报文
    std::string text_len_string = inbuffer.substr(0, pos); // 获取正文长度
    // 2.1遍历正文，查看有无非法数据
    if (text_len_string.empty())
        return false;
    for (const auto &c : text_len_string)
        if (c < '0' || c > '9')
            return false;

    int text_len = std::stoi(text_len_string);

    // 如果inbuffer.size() > text_len    说明inbufffer中必然有一个完整的报文
    int total_len = text_len_string.size() + LINE_SEP_LEN + text_len + LINE_SEP_LEN;
    if (inbuffer.size() < total_len)
    {
        std::cout << "输入的报文不完整，等待下一次输入:\n";
        return false;
    }

    // 3.到此。说明完整读取了一个报文
    *rcv_text = inbuffer.substr(0, total_len);
    inbuffer.erase(0, total_len);
    return true;
}

// 服务端接收，客户端发送的请求
class Request
{
public:
    Request(int x = 0, int y = 0, char op = 0)
        : _x(x), _y(y), _op(op) {}

    // 序列化可以自己写，也能调用系统接口k
    //  序列化自己,通过输入输出型参数获取序列化结果 结构化对象 -> x op y
    bool serialize(std::string *out)
    {
        // 自己的序列化
#ifdef MYSELF
        *out = "";
        std::string x_string = std::to_string(_x);
        std::string y_string = std::to_string(_y);

        *out += x_string;
        *out += SEP;
        *out += _op;
        *out += SEP;
        *out += y_string;
#else
        // json序列化
        // 1.定义k-v数据
        Json::Value root;
        root["first"] = _x;
        root["second"] = _y;
        root["oper"] = _op;

        // 定义writer将root数据转化为字符串数据
        Json::StreamWriterBuilder writer;
        // Json::StyledWriter writer;
        *out = Json::writeString(writer, root);
#endif
        return true;
    }

    // 反序列化自己,解析传入的序列化数据后写入结构体相应的数据中 将 xxxx op yyyy写入到我们的结构体数据中
    bool deserialize(const std::string &in)
    {
#ifdef MYSELF
        auto left = in.find(SEP);
        auto right = in.rfind(SEP);
        if (left == std::string::npos || right == std::string::npos || left == right)
            return false;

        std::string x_string = in.substr(0, left);
        std::string y_string = in.substr(right + SEP_LEN);

        if (x_string.empty())
            return false;
        if (y_string.empty())
            return false;

        // _x = atoi(x_string.c_str());
        // _y = atoi(y_string.c_str());
        _x = std::stoi(x_string);
        _y = std::stoi(y_string);
        _op = in[left + SEP_LEN];
#else
        // json反序列化
        Json::Value root;
        Json::CharReaderBuilder readerbuilder;
        std::unique_ptr<Json::CharReader> reader(readerbuilder.newCharReader());
        std::string err;
        reader->parse(in.data(), in.data() + in.size(), &root, &err);

        _x = root["first"].asInt();
        _y = root["second"].asInt();
        _op = root["oper"].asInt(); // 会自动转化为字符串传入op
#endif
        return true;
    }

public:
    // _x -op _y    人为规定的业务协议
    int _x;
    int _y;
    char _op;
};

// 服务端发送，客户端就收的回应
class Response
{
public:
    Response(int exitcode = -1, int result = 0)
        : _exitcode(exitcode), _result(result) {}

    // 序列化自己 _exitcode _result
    bool serialize(std::string *out)
    {
#ifdef MYSELF

        *out = "";
        std::string ec_string = std::to_string(_exitcode);
        std::string res_string = std::to_string(_result);

        *out = ec_string;
        *out += SEP;
        *out += res_string;
#else
        // json序列化
        Json::Value root;
        root["exitcode"] = _exitcode;
        root["result"] = _result;

        Json::StreamWriterBuilder writer;
        *out = Json::writeString(writer, root);
#endif
        return true;
    }
    // 反序列化自己 _exitcode _result
    bool deserialize(std::string &in)
    {
#ifdef MYSELF

        auto pos = in.find(SEP);
        if (pos == std::string::npos)
            return false;

        std::string ec_string = in.substr(0, pos);
        std::string res_string = in.substr(pos + 1);
        if (ec_string.empty() || res_string.empty())
            return false;

        _exitcode = std::stoi(ec_string);
        _result = std::stoi(res_string);
#else
        // json反序列化
        Json::Value root;

        Json::CharReaderBuilder readerbuilder;                                   // 创建读取建造者
        std::unique_ptr<Json::CharReader> reader(readerbuilder.newCharReader()); // 创建读取者

        // 读取数据
        std::string err;
        reader->parse(in.c_str(), in.data() + in.size(), &root, &err);

        _exitcode = root["exitcode"].asInt();
        _result = root["result"].asInt();
#endif
        return true;
    }

public:
    int _exitcode; // 0->计算成功  !0 -> 表示计算失败。1，2，3各个表示多个，是由人定义的标准
    int _result;
};
